home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
001-025
/
disk_020
/
porthandler
/
porthandler.asm
< prev
next >
Wrap
Assembly Source File
|
1992-05-06
|
13KB
|
462 lines
TTL "Port-Handler AmigaDos Device Driver"
* Port-handler AmigaDos Device Driver
* Copyright (c) 1986 John A. Toebes, VIII All Rights Reserved
*
* Permission is granted for personal usage only.
* This program may not be incorporated in any commercial product or sold
* for any purpose without the permission of the author.
*
SECTION CODE
StartModule DC.L (EndModule-StartModule)/4
EntryPt EQU *
*
NOLIST
INCLUDE "exec/types.i"
INCLUDE "exec/libraries.i"
INCLUDE "exec/io.i"
INCLUDE "libraries/dosextens.i"
LIST
INCLUDE "bcpl.i"
***
*** Global constants used
***
FALSE EQU 0
TRUE EQU -1
IOB_size EQU 30
RAW_NAME EQU ('R'<<24)!('A'<<16)!('W'<<8)
MARKER1_DATA EQU ('T'<<24)!('O'<<16)!('P'<<8)!('!')
MARKER2_DATA EQU ('J'<<24)!('O'<<16)!('H'<<8)!('N')
***
*** This is the global structure that we get a pointer to in A1
*** when our code is executing
***
STRUCTURE PORT_HANDLER_GLOBALS,0
LONG IO_parm_pkt *Pointer to our initial packet
* LONG MARKER1
* LONG EXECLIB
* LONG OURCODE
* LONG DOSCALL
* LONG DOSRET
LONG read_pkt *Pointer to user read request
LONG write_pkt *Pointer to user write request
BYTE openin *device is open for input
BYTE openout *device is open for output
WORD FILLER * to pad to a 4 byte boundary
BPTR node *pointer to our DeviceList node
BPTR inpkt *pointer to read transmission pkt
STRUCT inpkt_buf,16 * Buffer for above
BPTR outpkt *pointer to write transmission pkt
STRUCT outpkt_buf,16 * Buffer for above
BPTR IOB *IO request for reading from device
STRUCT IOB_buf,(IOB_size*4)+8 * Buffer for above
BPTR IOBO *IO request for writing to device
STRUCT IOBO_buf,(IOB_size*4)+8 * Buffer for above
APTR dataloc *QUE pointer-data to be written/read
BPTR tpkt *QUE pointer-IO completion msg packet
BPTR use_IOB *QUE pointer-IOB for IO
* LONG MARKER2
BPTR FILLER1
LABEL FRAME_SIZE
*
* This routine is a sample device handler for
* SER: The serial port
* PAR: The parallel port
* PRT: The installed printer
* PRT:RAW The installed printer without translating LF to CR
*
* BCPL driver Entry conditions:
* D1 - DosPacket - immediately converted to a real pointer
* A0 - 0
* A1 - Pointer to our global data area
* A2 - Pointer to BCPL subroutine library
* A3 - <Unassigned>
* A4 - Pointer to Base of out code
* A5 - Pointer to Subroutine transfer vector
* A6 - Pointer to Code termination vector
*
* Upon initialization, D1 contains a BPTR to a DosPacket with the info:
* arg1 = BPTR to BCPL string of device name
* This is should be one of PRT: PRT:RAW SER: PAR:
* arg2 = Extra info from the DevList entry.
* 0 = SER: 1 = PAR: 2 = PRT:
* arg3 = BPTR to the DevList entry
*
LSL.L #2,D1 *make pointer to DosPacket real
* Initialize our global structure
* MOVE.L A1,$CA
* MOVE.L #MARKER1_DATA,MARKER1(A1) *let us see it in memory
* MOVE.L #MARKER2_DATA,MARKER2(A1)
* MOVE.L A2,EXECLIB(A1)
* MOVE.L A4,OURCODE(A1)
* MOVE.L A5,DOSCALL(A1)
* MOVE.L A6,DOSRET(A1)
CLR.L read_pkt(A1) *No Read request pending
CLR.L write_pkt(A1) *No write request pending
CLR.B openin(A1) *device not opened for input
CLR.B openout(A1) *device not opened for output
MOVE.L dp_Arg3(A0,D1.L),D3
LSL.L #2,D3 *make it a real pointer
MOVE.L D3,node(A1) *to our DevList entry
MOVEQ.L #inpkt_buf,D3 *locate our default input packet
ADD.L A1,D3
MOVE.L #act_queueread,dp_Type(A0,D3.L) *and set it as a read packet
LSR.L #2,D3
MOVE.L D3,inpkt(A1)
MOVEQ.L #outpkt_buf,D4 *locate our default output packet
ADD.L A1,D4
MOVE.L #act_queuewrite,dp_Type(A0,D4.L) *and set as write packet
LSR.L #2,D4
MOVE.L D4,outpkt(A1)
MOVEQ.L #IOB_buf,D5 *locate our input IO request packet
ADD.L A1,D5
LSR.L #2,D5
MOVE.L D5,IOB(A1)
MOVE.L #IOBO_buf,D6 *locate our output IO request packet
ADD.L A1,D6
LSR.L #2,D6
MOVE.L D6,IOBO(A1)
MOVEQ.L #IOB_size-1,D5 *Empty our input IOB
LEA IOB_buf(A1),A3
CLRIOB CLR.L (A3)+
DBF D5,CLRIOB
*** Open the device
*** We have to figure out what device we will be opening
MOVEQ.L #0,D4 * Flags on the open
MOVE.L D4,D3 * Unit number
TST.L dp_Arg2(A0,D1.L) * is it a open on SER:
BEQ IS_SER
MOVEQ.L #1,D2
CMP.L dp_Arg2(A0,D1.L),D2 * is it an open on PAR:
BEQ IS_PAR
IS_PRT LEA prt_name(A4),A3 PRT: uses printer.device
BRA PUTNAME
IS_SER LEA ser_name(A4),A3 SER: uses serial.device
BRA PUTNAME
IS_PAR LEA par_name(A4),A3 PAR: uses parallel.device
PUTNAME EQU *
MOVE.L A3,D2
LSR.L #2,D2 *make the name a BPTR
MOVE.L IOB(A1),D1
BCALL OpenDevice
TST.L D1 *did the open succeed
BNE GOTOPEN *no...
MOVE.L #ERROR_OBJECT_IN_USE,D3 *say it is in use
MOVEQ.L #FALSE,D2
MOVE.L (A1),D1
BCALL returnpkt
BEXIT
GOTOPEN EQU *
MOVEQ.L #IOB_size-1,D5 *get a second IOB for output
LEA IOB_buf(A1),A3
LEA IOBO_buf(A1),A0 *Use only for copying - restore to 0 later
COPYIOB MOVE.L (A3)+,(A0)+
DBF D5,COPYIOB
MOVEQ.L #0,D5
MOVE.L D5,A0
*** Now see if they asked to put the printer into the RAW mode
MOVE.L (A1),D1
LSL.L #2,D1
MOVEQ.L #2,D5
CMP.L dp_Arg2(A0,D1.L),D5 * is it a open on PRT:
BNE NOTRAW
MOVE.L dp_Arg1(A0,D1.L),D3
LSL.L #2,D3
CMP.L #RAW_NAME,4(A0,D3.L) *is the secondpart 'RAW\0'?
BNE NOTRAW
*** Build the IOB for outputing the initialization string
LEA prt_init_str(A4),A3 *point to the output string
MOVE.L A3,D3
MOVE.L IOBO(A1),D1
ASL.L #2,D1
MOVE.L D1,A3
MOVE.W #CMD_WRITE,D2
MOVE.L D2,IO_COMMAND(A3) ;$1C
MOVE.L D3,IO_DATA(A3) ;$28
MOVEQ.L #-1,D4
MOVE.L D4,IO_LENGTH(A3) ;$24
MOVE.L IOBO(A1),D1 *DOIO(IOBO) to output the init string
BCALL DoIO
NOTRAW EQU *
*** set taskid field to our task so everyone comes to us for the device
BCALL taskid
MOVE.L node(A1),D2
MOVE.L D1,dl_Task(A0,D2.L)
*** We are now setup, return our initilization packet so we can
*** Let the system start sending us IO requests
MOVEQ.L #TRUE,D2
MOVE.L (A1),D1 IO_parm_pkt
BCALL returnpkt
*** Now that all the initialization is done, here is where we do all
*** the work of processing the requests. Of importance to note is that
*** although we have opened the device, the real request to open the
*** device comes (usually) as the first message to our task.
***
*** Events come to us in the form of a DosMessage with the type of
*** event in the type field of the packet
*** We only need to handle a few of these events and can just send
*** the rest back as invalid requests
***
*** The ones we handle are:
*** 'R' - A request to read from the device
*** 'W' - A request to write to a device
*** 1001 - A read WE posted to the device completed
*** 1002 - A write WE posted to the device completed
*** 1005 - The user wishes to open the device we handle for input
*** 1006 - The user wishes to open the device we handle for output
*** 1007 - The uses wishes to terminate an open on our device
***
*** Register usage:
*** D1 - BCPL pointer to event message packet
*** D2 - real pointer to event message packet - until changed
***
*** Wait for the next message
LOOP EQU *
BCALL taskwait
MOVE.L D1,D2
LSL.L #2,D2
*** Now see what type of message it was
MOVE.L dp_Type(A0,D2.L),D3
MOVEQ.L #'R',D4
CMP.L D4,D3 *read
BEQ do_R
MOVEQ.L #'W',D4
CMP.L D4,D3 *write
BEQ do_W
CMP.L #act_queueread,D3 *act.read
BEQ do_read
CMP.L #act_queuewrite,D3 *act.write
BEQ do_writ
CMP.L #act_findinput,D3 *find input
BEQ do_old
CMP.L #act_findoutput,D3 *find output
BEQ do_new
CMP.L #act_end,D3 *end
BEQ do_end
BRA do_dflt
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Open up our device for input
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_old TST.B openin(A1) *make sure it isn't already open for input
BNE IN_USE
ST openin(A1) *Say we have the device for input
MOVE.L #MODE_OLDFILE,D3
BRA SET_SCB
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Open up our device for output
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_new TST.B openout(A1)
BNE IN_USE
ST openout(A1) *Say we have the device for output
MOVE.L #MODE_NEWFILE,D3
SET_SCB MOVE.L dp_Arg1(A0,D2.L),D4
LSL.L #2,D4
MOVE.L D3,fh_Arg1(A0,D4.L) *and set the access mode
MOVEQ.L #TRUE,D5
MOVE.L D5,fh_Interactive(A0,D4.L) * Mark file as interactive
BRA OK_RET
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Close the device for input/output
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_end CMP.L #MODE_OLDFILE,dp_Arg1(A0,D2.L)
BNE closout
CLR.B openin(A1) *device no longer needed for input
BRA doclose
closout CLR.B openout(A1) *device no longer needed for output
doclose EQU *
*** If this closed both files then it is time to shut down
TST.B openin(A1)
BNE OK_RET
TST.B openout(A1)
BNE OK_RET
MOVE.L node(A1),D3 *find our devicelist entry
CLR.L dl_Task(A0,D3.L) *remove our process id from the entry
BRA OK_RET
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Here we have a read request we posted returning to us
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_read MOVE.L D1,inpkt(A1) *restore our packet for posting reads
MOVE.L read_pkt(A1),D1 *the message to return to the user
LEA IOB_buf(A1),A3 *the IO request that returned
BRA CHK_RET
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Here we have a write request we posted returning to us
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_writ MOVE.L D1,outpkt(A1) *restore out packet for posting writes
MOVE.L write_pkt(A1),D1 *the message to return to the user
LEA IOBO_buf(A1),A3 *the IO request that returned
CHK_RET MOVEQ.L #0,D3
MOVE.B IO_ERROR(A3),D3 *get the error code if any
BNE BAD_RET *any error?
MOVE.L IO_ACTUAL(A3),D2 *return number of bytes read
BRA RET_PKT
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Here we have a request from the user to do a read
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_R MOVE.L D1,read_pkt(A1)
MOVE.L inpkt(A1),tpkt(A1)
CLR.L inpkt(A1) *Indicate input in progress
MOVEQ.L #CMD_READ,D4
MOVE.L IOB(A1),D1
BRA QUE_PKT
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Here we have a request from the user to do a write
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_W MOVE.L D1,write_pkt(A1)
MOVE.L outpkt(A1),D3
CLR.L outpkt(A1) *Indicate an output is in progress
MOVEQ.L #CMD_WRITE,D4
MOVE.L IOBO(A1),D1
*** To queue an IO request we need to have set up:
*** D1 - BCPL pointer to the desired IOB
*** D2 - The real pointer to the input request message
*** D3 - message packet associated with the request
*** D4 - I/O request type to be queued
QUE_PKT MOVE.L D1,D5
ASL.L #2,D5
MOVE.L D5,A3
MOVE.W D4,IO_COMMAND(A3) ;$1C
MOVE.L dp_Arg2(A0,D2.L),IO_DATA(A3) ;$28
MOVE.L dp_Arg3(A0,D2.L),IO_LENGTH(A3) ;$24
CLR.L IO_OFFSET(A3) ;$28
MOVE.L D3,D2
BCALL SendIO
BRA LOOP
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
***
*** Here we handle all other requests we do not recognize
***
*** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
do_dflt TST.B openin(A1)
BNE BAD_ACT
TST.B openout(A1)
BNE BAD_ACT
MOVE.L node(A1),D1 *keep them from bothering us anymore
CLR.L dl_Task(A0,D1.L)
BAD_ACT EQU *
MOVE.L #ERROR_ACTION_NOT_KNOWN,D3
BRA BAD_RET
***
*** Here we return the message to the user
***
IN_USE MOVE.L #ERROR_OBJECT_IN_USE,D3 *the device is in use
BAD_RET MOVEQ.L #FALSE,D2 *Operation had failed
BRA RET_PKT
OK_RET MOVEQ.L #TRUE,D2 *Operation has succeeded
RET_PKT BCALL returnpkt *D1 already has the packet address in it
LOOPIT TST.B openin(A1) *is there anyone open on us?
BNE LOOP
TST.B openout(A1)
BNE LOOP
TST.L outpkt(A1) *or an output pending?
BEQ LOOP
TST.L inpkt(A1) *or an input pending?
BEQ LOOP
***
*** Our purpose in life is fullfilled, close the device
*** and quietly fade off into the sunset
***
MOVE.L IOB(A1),D1
BCALL CloseDevice
BEXIT
CNOP 0,4
ser_name EQU *-EntryPt
DC.B 14,'serial.device',0
CNOP 0,4
par_name EQU *-EntryPt
DC.B 16,'parallel.device',0
CNOP 0,4
prt_name EQU *-EntryPt
DC.B 15,'printer.device',0
CNOP 0,4
prt_init_str EQU *-EntryPt
DC.B $1B,'[20l',0
***
*** Trailer stuff to make this look like a BCPL module
***
CNOP 0,4
DC.L 0
DC.L 1
DC.L EntryPt-StartModule
DC.L (FRAME_SIZE/4)+2+$44
EndModule EQU *
END